package com.cellulam.framework.core.rest;

import com.alibaba.druid.util.PatternMatcher;
import com.alibaba.druid.util.ServletPathMatcher;
import com.google.common.base.Stopwatch;
import com.cellulam.framework.core.log.LogClient;
import com.cellulam.framework.core.log.RestLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.concurrent.TimeUnit;

public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    private final LogClient logClient;

    private PatternMatcher pathMatcher = new ServletPathMatcher();
    private final static Logger logger = LoggerFactory.getLogger(LoggingClientHttpRequestInterceptor.class);

    public LoggingClientHttpRequestInterceptor(LogClient logClient) {
        this.logClient = logClient;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        Exception ex = null;

        Stopwatch sp = Stopwatch.createStarted();
        ClientHttpResponse response = null;
        try {
            response = execution.execute(request, body);
        } catch (Exception e) {
            logger.error("", e);
            ex = e;
        } finally {
            long cost = sp.stop().elapsed(TimeUnit.MILLISECONDS);
            writeLog(request, body, ex, cost, response);
        }
        return response;
    }

    private void writeLog(HttpRequest request, byte[] body, Exception ex, long cost, ClientHttpResponse response) throws IOException {

        URI uri = request.getURI();
        HttpMethod method = request.getMethod();
        HttpHeaders requestHeaders = request.getHeaders();
        String requestBody = new String(body, "UTF-8");

        HttpStatus responseStatus = response.getStatusCode();
        String responseStatusText = response.getStatusText();
        HttpHeaders responseHeaders = response.getHeaders();
        String responseBody = this.getBody(response);

        logger.debug("===========================request begin================================================");
        logger.debug("URI         : {}", uri);
        logger.debug("Method      : {}", method);
        logger.debug("Headers     : {}", requestHeaders);
        logger.debug("Request body: {}", requestBody);
        logger.debug("==========================request end================================================");

        logger.debug("============================response begin==========================================");
        logger.debug("cost  : {}", cost);
        logger.debug("Status code  : {}", responseStatus);
        logger.debug("Status text  : {}", responseStatusText);
        logger.debug("Headers      : {}", responseHeaders);
        logger.debug("Response body: {}", responseBody);
        logger.debug("=======================response end=================================================");

        this.logClient.writeRestLog(RestLog
                .builder()
                .uri(uri)
                .method(method)
                .requestHeaders(requestHeaders)
                .requestBody(requestBody)
                .cost(cost)
                .responseStatus(responseStatus == null ? -1 : responseStatus.value())
                .responseStatusText(responseStatusText)
                .responseHeaders(responseHeaders)
                .responseBody(responseBody)
                .build(), ex);
    }

    private String getBody(ClientHttpResponse response) throws IOException {
        StringBuilder inputStringBuilder = new StringBuilder();
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                inputStringBuilder.append(line);
                inputStringBuilder.append('\n');
                line = bufferedReader.readLine();
            }
        }
        return inputStringBuilder.toString();
    }
}
